Skip to content

Publish the service images as zstd rather than gzip - #369

Merged
davidmckayv merged 1 commit into
mainfrom
zstd-layers
Sep 4, 2026
Merged

Publish the service images as zstd rather than gzip#369
davidmckayv merged 1 commit into
mainfrom
zstd-layers

Conversation

@davidmckayv

Copy link
Copy Markdown
Contributor

Ahead of cutting 0.0.7, so the release publishes zstd images rather than needing a second release to get them.

What changes

One exporter string on the component-images job: oci-mediatypes=true,compression=zstd,force-compression=true.

force-compression is the part that matters. Without it only our own thin layers change and the saving rounds to nothing, because almost every byte came from Playwright's base image. With it those base layers are recompressed.

The numbers, measured not estimated

agent-computer, arm64, pushed to a throwaway registry both ways:

wire size
gzip 962 MB
zstd 886 MB

76 MB, 8%. The larger win is inflation speed, which zstd does several times faster than gzip, and that lands on 2 GB of Chromium on somebody's laptop during setup.

Only the component images

ghcr.io/copilotkit/openbot stays gzip. Reading a zstd layer needs a client that supports it: Podman and current containerd do, older Docker does not. The five component images are pulled by an installer that ships Podman; the single image is pulled by deployments running whatever they have.

The cost, stated: these images no longer share layers with a gzip pull of the same base.

Verified against ghcr.io, not at the next release

A throwaway image pushed with this exact exporter string:

  • both architectures pushed by digest, accepted
  • imagetools create merged them into application/vnd.oci.image.index.v1+json
  • layers report application/vnd.oci.image.layer.v1.tar+zstd, including the base layer, which is what proves force-compression reached it
  • docker pull --platform linux/amd64 and linux/arm64 both succeeded from the merged tag

zizmor --min-confidence low clean, workflow YAML parses, format:check clean.

One cleanup I could not do

That probe left a private package, openbot-zstd-probe, in the org's registry. My token lacks delete:packages, so it needs removing by hand: https://github.com/orgs/CopilotKit/packages/container/package/openbot-zstd-probe

A pull was already a compressed transfer, so this is a better algorithm for
the same job rather than compression where there was none. Measured on
`agent-computer`, which is where the bytes are: 962 MB becomes 886 MB, and zstd
inflates several times faster, which is worth more on 2 GB of Chromium than the
8% is.

`force-compression=true` is the part that matters. Without it only our own thin
layers change and the saving rounds to nothing, because almost every byte came
from Playwright's base image. With it those layers are recompressed, which also
means these images stop sharing layers with a gzip pull of the same base.

Only the five component images. Reading a zstd layer needs a client that
supports it, which Podman and current containerd do, and the installer ships
Podman. `ghcr.io/copilotkit/openbot` is pulled by deployments running whatever
they have, so it stays gzip.

Verified against ghcr.io before merging rather than at the next release: both
architectures pushed by digest with this exact exporter string, merged into one
OCI index, layers reported as
`application/vnd.oci.image.layer.v1.tar+zstd` including the base layer, and
`docker pull --platform` succeeded for both.
@davidmckayv davidmckayv added the full-ci Run the slow image builds on this PR label Sep 4, 2026
@davidmckayv
davidmckayv merged commit 31e7fb9 into main Sep 4, 2026
15 checks passed
@davidmckayv
davidmckayv deleted the zstd-layers branch September 4, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

full-ci Run the slow image builds on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant